﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using AdoNet = System.Data;
using System.Runtime.CompilerServices;

namespace DataSet4Com
{
    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.AutoDispatch)]
    [ComDefaultInterface(typeof(IConstraintCollection))]
    [Guid("9654CDDE-470A-402A-8403-F20BA0BC229F")]
    public class ConstraintCollection : IConstraintCollection
    {
        private AdoNet.ConstraintCollection _adoNetConstraintCollection;

        public ConstraintCollection() : this(null) { }

        public ConstraintCollection(AdoNet.ConstraintCollection adoNetConstraintCollection)
        {
            if (adoNetConstraintCollection == null)
                throw new ArgumentNullException("adoNetConstraintCollection");
            else
                _adoNetConstraintCollection = adoNetConstraintCollection;
        }

        [ComVisible(false)]
        public AdoNet.ConstraintCollection AdoNetConstraintCollection
        {
            get { return _adoNetConstraintCollection; }
        }

        private List<IConstraint> GetWrappedConstraintAdoNetCollection()
        {
            List<IConstraint> constraints = new List<IConstraint>();

            foreach (AdoNet.Constraint adoNetConstraint in _adoNetConstraintCollection)
            {
                if (adoNetConstraint is AdoNet.ForeignKeyConstraint)
                    constraints.Add(new ForeignKeyConstraint((AdoNet.ForeignKeyConstraint)adoNetConstraint));
                else if (adoNetConstraint is AdoNet.UniqueConstraint)
                    constraints.Add(new UniqueConstraint((AdoNet.UniqueConstraint)adoNetConstraint));
                else
                    throw new InvalidOperationException(string.Format("Unsupported constraint type '{0}'.", adoNetConstraint.GetType().Name));
            }
            return constraints;
        }

        [DispId(-4)]
        public IEnumerator GetEnumerator()
        {            
            return GetWrappedConstraintAdoNetCollection().GetEnumerator();
        }

        [DispId(0)]
        [IndexerName("_Default")]
        public IConstraint this[int index]
        {
            get
            {
                return GetWrappedConstraintAdoNetCollection()[index];
            }
        }

        public IConstraint GetConstraintByName(string constraintName)
        {
            IConstraint wrappedConstraint = (from constraint in GetWrappedConstraintAdoNetCollection()
                                             where constraint.ConstraintName.Equals(constraintName)
                                             select constraint).First();

            return wrappedConstraint;
        }

        public void AddConstraint(IConstraint constraint)
        {
            _adoNetConstraintCollection.Add(constraint.AdoNetConstraint);
        }
        
        public IConstraint AddUniqueConstraint(string name, DataColumnList columns, bool primaryKey)
        {
            AdoNet.DataColumn[] adoNetColumns = (from column in columns.InternalList
                                                 select column.AdoNetDataColumn).ToArray();

            return (IConstraint)new UniqueConstraint
            (
                (AdoNet.UniqueConstraint)_adoNetConstraintCollection.Add
                (
                    name,
                    adoNetColumns,
                    primaryKey                                            
                )
            );
        }

        public IConstraint AddForeignKeyConstraint(string name, DataColumnList primaryKeyColumns, DataColumnList foreignKeyColumns)
        {
            AdoNet.DataColumn[] adoNetPrimaryKeyColumns = (from column in primaryKeyColumns.InternalList
                                                           select column.AdoNetDataColumn).ToArray();

            AdoNet.DataColumn[] adoNetForeignKeyColumns = (from column in foreignKeyColumns.InternalList
                                                           select column.AdoNetDataColumn).ToArray();

            return (IConstraint)new UniqueConstraint
            (
                (AdoNet.UniqueConstraint)_adoNetConstraintCollection.Add
                (
                    name,
                    adoNetPrimaryKeyColumns,
                    adoNetForeignKeyColumns
                )
            );
        }

        public bool CanRemove(IConstraint constraint)
        {
            return _adoNetConstraintCollection.CanRemove(constraint.AdoNetConstraint);
        }

        public void Clear()
        {
            _adoNetConstraintCollection.Clear();
        }

        public bool Contains(string name)
        {
            return _adoNetConstraintCollection.Contains(name);
        }

        public int IndexOfByConstraint(IConstraint constraint)
        {
            return _adoNetConstraintCollection.IndexOf(constraint.AdoNetConstraint);
        }

        public int IndexOf(string constraintName)
        {
            return _adoNetConstraintCollection.IndexOf(constraintName);
        }

        public void RemoveConstraint(IConstraint constraint)
        {
            _adoNetConstraintCollection.Remove(constraint.AdoNetConstraint);
        }

        public void Remove(string name)
        {
            _adoNetConstraintCollection.Remove(name);
        }

        public void RemoveAt(int index)
        {
            _adoNetConstraintCollection.RemoveAt(index);
        }

        public int Count
        {
            get { return _adoNetConstraintCollection.Count; }
        }
    }

    [ComVisible(true)]
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    [Guid("3FD19232-6DAB-43E0-AAF4-A54A1F7987BB")]
    public interface IConstraintCollection
    {
        [DispId(-4)]
        IEnumerator GetEnumerator();

        [DispId(0)]
        [IndexerName("_Default")]
        IConstraint this[int index]
        {
            get;
        }

        IConstraint GetConstraintByName(string name);

        void AddConstraint(IConstraint constraint);

        IConstraint AddUniqueConstraint(string name, DataColumnList columns, bool primaryKey);

        IConstraint AddForeignKeyConstraint(string name, DataColumnList primaryKeyColumns, DataColumnList foreignKeyColumns);               

        bool CanRemove(IConstraint constraint);

        void Clear();

        bool Contains(string name);

        int IndexOfByConstraint(IConstraint constraint);

        int IndexOf(string constraintName);

        void RemoveConstraint(IConstraint constraint);

        void Remove(string name);

        void RemoveAt(int index);

        int Count
        {
            get;
        }
    }
}
